/*
 * Copyright 2025 mingliqiye
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ProjectName mingli-utils
 * ModuleName mingli-utils.main
 * CurrentFile Debouncer.java
 * LastUpdate 2025-09-09 08:37:34
 * UpdateUser MingLiPro
 */

package com.mingliqiye.utils.functions;

import java.util.concurrent.*;

/**
 * 防抖器类，用于实现防抖功能，防止在短时间内重复执行相同任务
 *
 * @author MingLiPro
 */
public class Debouncer {

	private final ScheduledExecutorService scheduler =
		Executors.newSingleThreadScheduledExecutor();
	private final ConcurrentHashMap<Object, Future<?>> delayedMap =
		new ConcurrentHashMap<>();
	private final long delay;

	/**
	 * 构造函数，创建一个防抖器实例
	 *
	 * @param delay 延迟时间
	 * @param unit  时间单位
	 */
	public Debouncer(long delay, TimeUnit unit) {
		this.delay = unit.toMillis(delay);
	}

	/**
	 * 执行防抖操作，如果在指定延迟时间内再次调用相同key的任务，则取消之前的任务并重新计时
	 *
	 * @param key  任务的唯一标识符，用于区分不同任务
	 * @param task 要执行的任务
	 */
	public void debounce(final Object key, final Runnable task) {
		// 提交新任务并获取之前可能存在的任务
		final Future<?> prev = delayedMap.put(
			key,
			scheduler.schedule(
				() -> {
					try {
						task.run();
					} finally {
						// 任务执行完成后从映射中移除
						delayedMap.remove(key);
					}
				},
				delay,
				TimeUnit.MILLISECONDS
			)
		);

		// 如果之前存在任务，则取消它
		if (prev != null) {
			prev.cancel(true);
		}
	}

	/**
	 * 关闭防抖器，取消所有待执行的任务并关闭调度器
	 */
	public void shutdown() {
		// 先取消所有延迟任务
		for (Future<?> future : delayedMap.values()) {
			future.cancel(true);
		}
		delayedMap.clear();

		// 再关闭调度器
		scheduler.shutdownNow();
	}
}
